<?php

/**
 * Created by Zhy
 * User: Zhy
 * Date: 2020/3/3
 * Time: 10:51
 */
namespace tixian\WX;

class Weixin
{
    // 请求地址
    public $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
    
    // 商户平台秘钥
    public $key;
    
    // 商户的appid
    public $mch_appid;
    
    // 商户号
    public $mchid;
    
    public function __construct($config = [])
    {
        $this->key = $config['key'];
        $this->mch_appid = $config['mch_appid'];
        $this->mchid = $config['mchid'];
    }
    
    /**
     * 提现
     * @param $order_num           订单号
     * @param $withdraw_openid     用户唯一标识
     * @param $real_name           真实姓名
     * @param $price               提现金额
     * @return \SimpleXMLElement
     */
    public function wxTiXian($order_num, $withdraw_openid, $real_name, $price){
        $data = [];
        // 商户号的appid
        $data['mch_appid'] = $this->mch_appid;
        // 商户号
        $data['mchid'] = $this->mchid;
        // 随机数
        $data['nonce_str'] = $this->getRandChar(32);
        // 订单号
        $data['partner_trade_no'] = $order_num;
        // 用户的唯一标识
        $data['openid'] = $withdraw_openid;
        // 是否校验真实姓名  FORCE_CHECK:强制校验   NO_CHECK:不校验
        $data['check_name'] = 'FORCE_CHECK';
        // 真实姓名
        $data['re_user_name'] = $real_name;
        // 金额
        $data['amount'] = $price * 100;
        // 备注
        $data['desc'] = '用户提现';
        // ip地址
        $data['spbill_create_ip'] = request()->ip();
        // 签名
        $data['sign'] = $this->makeSign($data, $this->key);
        // 将数据转换成xml格式
        $xml = $this->toXml($data);
        // 将生成的xml数据进行请求
        $response = $this->httpRequest($this->url, $xml);
        $rdata = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
    
        return $rdata;
    }
    
    /*
     * 发送请求
     * @param  string $url      请求的url地址
     * @param  array  $postData 请求的数据
     */
    public function httpRequest($url, $postData = [])
    {
        $header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
        // 初始化curl
        $ch = curl_init();
        // 设置请求的url地址
        curl_setopt($ch, CURLOPT_URL, $url);
        // 将curl_exec()获取的信息以字符串返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // 发送post请求
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        //curl注意事项，如果发送的请求是https，必须要禁止服务器端校检SSL证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLCERT,ROOT_PATH.'/public/apiclient_cert.pem');
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLKEY,ROOT_PATH.'/public/apiclient_key.pem');
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        
        // 执行curl
        $result = curl_exec($ch);
        if(curl_errno($ch)){
            print curl_error($ch);
        }
        // 关闭curl
        curl_close($ch);
        
        return $result;
    }
    
    /**
     * 生成签名
     * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function makeSign($data, $key){
        // 去空
        $data=array_filter($data);
        //签名步骤一：按字典序排序参数
        ksort($data);
        $string_a=http_build_query($data);
        $string_a=urldecode($string_a);
        //签名步骤二：在string后加入KEY
        $string_sign_temp=$string_a."&key=".$key;
        //签名步骤三：MD5加密
        $sign = md5($string_sign_temp);
        // 签名步骤四：所有字符转为大写
        $result=strtoupper($sign);
        return $result;
    }
    
    /**
     * 输出xml字符
     * @throws WxPayException
     **/
    public function toXml($data){
        //var_dump($data);
        if(!is_array($data) || count($data) <= 0){
            //throw new WxPayException("数组数据异常！");
        }
        $xml = "<xml>";
        foreach ($data as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }
    
    /**
     * 将xml转为array
     * @param  string $xml xml字符串
     * @return array       转换得到的数组
     */
    public function toArray($xml){
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $result;
    }
    
    /**
     * 获取指定长度的随机字符串
     * @param $length
     * @return null|string
     */
    function getRandChar($length){
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol)-1;
        for($i=0;$i<$length;$i++){
            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }
        return $str;
    }
}